package Vmov
import chisel3._
import chisel3.util._
import VMov._

object VMov{
  def WIDTH128 = 128
  def WIDTH64 = 64
  def WIDTH32 = 32
  def UMOV_32               =     BitPat("b00001110000?????001111??????????")
  def UMOV_64               =     BitPat("b01001110000?1000001111??????????")
  def SMOV_32               =     BitPat("b00001110000?????001011??????????")
  def SMOV_64               =     BitPat("b01001110000?????001011??????????")
  def MOVI_8                =     BitPat("b0?00111100000???111001??????????")
  def MOVI_32               =     BitPat("b0?00111100000???0??001??????????")
  def MOVI_16               =     BitPat("b0?00111100000???10?001??????????")
  def MOVI_32m              =     BitPat("b0010111100000???111001??????????")
  def MOVI_64               =     BitPat("b011111110???????010001??????????")
  def MOVI_128              =     BitPat("b0110111100000???111001??????????")

  def Mov(op: UInt, index: UInt, esize: Int): UInt = {
    val vecOp = op.asTypeOf(Vec(op.asBools.size, Bool()))
    val slice = (0 until esize).map(i => vecOp(index * esize.asUInt + i.asUInt))
    Cat(slice.reverse)
  }

//  def Mov_Elem2(operand: UInt, e: Int, esize: Int) :UInt = {
//    val op = UInt(esize.W)
//    //    for (e <- 0 until index) {
//    op := operand(esize * e + esize - 1, esize * e)
//    //    }
//    op
//  }

}

class SrcData extends Bundle{
  val oprand1_low = UInt(64.W)
  val oprand1_hig = UInt(64.W)
  val oprand2_low = UInt(64.W)
  val oprand2_hig = UInt(64.W)
}

class DstData extends Bundle{
  val Wd = UInt(32.W)
  val Xd = UInt(64.W)
}

class VMov(val sec: UInt = 1.U) extends Module {
  val io = IO(new Bundle() {
    val inst = Input(UInt(WIDTH32.W))
    val srcData = Input(new SrcData())

    val dstData = Output(new DstData())
  })

  val UMov32_Hit = io.inst === UMOV_32
  val UMov64_Hit = io.inst === UMOV_64
  val SMov32_Hit = io.inst === SMOV_32
  val SMov64_Hit = io.inst === SMOV_64
  val MovI8_Hit = io.inst === MOVI_8
  val MovI32_Hit = io.inst === MOVI_32
  val MovI16_Hit = io.inst === MOVI_16
  val MovI32m_Hit = io.inst === MOVI_32m
  val MovI64_Hit = io.inst === MOVI_64
  val MovI128_Hit = io.inst === MOVI_128

  val Q = io.inst(30)
  val imm5 = io.inst(20,16)

  val UMovFlag = UMov32_Hit || UMov64_Hit
  val SMovFlag = SMov32_Hit || SMov64_Hit
  val MovIFlag = MovI8_Hit || MovI32_Hit || MovI16_Hit ||
    MovI32m_Hit || MovI64_Hit || MovI128_Hit

  //single data bit

  val UMovSize = MuxCase(0.U, Seq(
    (Cat(Q, imm5) === BitPat("b0????1")) -> 0.U,
    (Cat(Q, imm5) === BitPat("b0???10")) -> 1.U,
    (Cat(Q, imm5) === BitPat("b0??100")) -> 2.U,
    (Cat(Q, imm5) === BitPat("b1?1000")) -> 3.U
  ))

  val SMovSize = MuxCase(0.U, Seq(
    (Cat(Q, imm5) === BitPat("b?????1"))  -> 0.U,
    (Cat(Q, imm5) === BitPat("b????10"))  -> 1.U,
    (Cat(Q, imm5) === BitPat("b1??100"))  -> 2.U
  ))

  val size = Mux(UMovFlag, UMovSize, SMovSize)

  val idxdsize = Mux(imm5(4) === 1.U, 128.U, 64.U)

//  val index = imm5(4, size+1).asUInt
  val index0 = imm5(4,1)  //size = 0
  val index1 = imm5(4,2)  //size = 1
  val index2 = imm5(4,3)  //size = 2
  val index3 = imm5(4,4)  //size = 3

  val index = MuxCase(0.U, Seq(
    (size === 0.U) -> index0,
    (size === 1.U) -> index1,
    (size === 2.U) -> index2,
    (size === 3.U) -> index3
  ))

  val datasize = Mux(Q, 64.U, 32.U)
  val esize = 8.U << size

  val src = Mux(sec === 1.U, io.srcData.oprand1_low(63,0), io.srcData.oprand1_hig(63,0))
  val WbVaild = Mux(sec === 1.U, 1.U,
                  Mux(sec === 2.U , Mux(imm5(4) === 1.U, 1.U, 0.U),
                    0.U))




}

object VMov_Gen extends App {
  println("Generating the adder hardware")
  emitVerilog(new VMov(), Array("--target-dir", "generated/VMov/"))
}